Skip to content

fix(fetch): sanitize header tuples to fix Node.js 24 compatibility#766

Open
KrantiPonala wants to merge 1 commit intomswjs:mainfrom
KrantiPonala:fix/node-24-headers-extra-arg
Open

fix(fetch): sanitize header tuples to fix Node.js 24 compatibility#766
KrantiPonala wants to merge 1 commit intomswjs:mainfrom
KrantiPonala:fix/node-24-headers-extra-arg

Conversation

@KrantiPonala
Copy link
Copy Markdown

Node.js 24 internally passes a third boolean argument to Headers.prototype.set() and .append(). This extra argument was being recorded in raw header tuples, causing "Headers constructor: expected name/value pair to be length 2, found 3" errors when those tuples were later passed to the Headers constructor.

  • Only record [name, value] in set/append proxies, ignoring extra args
  • Sanitize header tuples when cloning Headers instances

Fixes #762

Node.js 24 internally passes a third boolean argument to
Headers.prototype.set() and .append(). This extra argument was being
recorded in raw header tuples, causing "Headers constructor: expected
name/value pair to be length 2, found 3" errors when those tuples were
later passed to the Headers constructor.

- Only record [name, value] in set/append proxies, ignoring extra args
- Sanitize header tuples when cloning Headers instances

Fixes mswjs#762
@kettanaito kettanaito changed the title fix(headers): sanitize header tuples to fix Node.js 24 compatibility fix(fetch): sanitize header tuples to fix Node.js 24 compatibility Feb 13, 2026
// Use only the first two arguments (name, value) to record raw headers.
// Node.js 24+ may pass additional internal arguments that should not
// be included in the raw headers array.
recordRawHeader(thisArg, [args[0], args[1]], 'append')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a reference to Node.js implementation of those additional arguments to Headers? What do they affect?

By not recording them, are we risking recreating a Headers instance that's not a 1-1 representation of the one recorded?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 3rd boolean argument is passed internally during Headers operations — it's not part of the public Headers API spec which only defines set(name, value) and append(name, value) with 2 arguments.

Regarding 1-1 representation: No risk here. The boolean is purely internal (likely for validation skipping or provenance tracking). It's never exposed through any public Headers API (entries(), get(), forEach(), etc.), so it cannot affect actual header name/value data. The recorded raw headers will still be a 1-1 representation of the actual header data.

// Use only the first two arguments (name, value) to record raw headers.
// Node.js 24+ may pass additional internal arguments that should not
// be included in the raw headers array.
recordRawHeader(thisArg, [args[0], args[1]], 'append')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are your thoughts on doing args.slice(0, 2)? I suppose we can benchmark which would be faster here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to change it to args.slice(0, 2) if you prefer — it's arguably more readable and explicitly conveys "take first 2 elements."

Performance-wise, [args[0], args[1]] is marginally faster (direct property access vs method call), but the difference is negligible in this context.

Let me know your preference and I'll update the PR.

@KrantiPonala
Copy link
Copy Markdown
Author

Could you review the changes @kettanaito. This fix would help us move forward with node24 upgrade in our repo. thanks!

@KrantiPonala
Copy link
Copy Markdown
Author

hey @kettanaito , were you able to review this PR. Would need help in merging this. Kindly review at the earliest. So we could use node24 in our repo. This is a blocker for us to move forward.

@jcaracciolo
Copy link
Copy Markdown

Looking for some movement on this @kettanaito

I looked into the "third parameter" behavior that this PR addresses. In Node.js 24+, the public Headers constructor (new Headers(...)) is strict and only accepts 2-tuples ([name, value]). Passing 3-tuples now throws:

Headers constructor: expected name/value pair to be length 2, found 3

The extra value we were seeing is not part of the Fetch API. It comes from Undici's internal header handling (HeadersList). For example, Undici uses an internal flag in redirect logic:

request.headersList.delete("proxy-authorization", true);

That second argument (true) is an internal signal for proxy-authentication handling. It is not part of the public Fetch Headers API. You can see similar vendored Undici logic here

This behavior implements the most likely the Fetch spec's authentication entries rules: https://fetch.spec.whatwg.org/#authentication-entries. Related Undici advisory: GHSA-3787-6prv-h9w3

Because the Fetch standard only defines headers as (name, value) pairs, normalizing headers (i.e., stripping additional metadata before constructing a Headers instance) is correct and expected.
Dropping the third value does not change observable behaviour. The proxy/auth distinction is re-derived internally by Undici based on the header name (e.g. proxy-authorization).

@jcaracciolo
Copy link
Copy Markdown

@kettanaito Bumping this so it doesn't get closed out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Node 24: Headers constructor: expected name/value pair to be length 2, found 3.

3 participants